#!/usr/bin/env python
# coding=UTF-8
import random
import logging
import json
import time
import urllib
import datetime
import itertools
from threading import Timer

import redisco
from redisco.containers import List, Hash

from tools import nsq_pub, json_encode
import config
import dao

def get_last_data(reader,bid, uid, data):
    uid = str(uid)
    user_info = Hash("%s_%s" % (bid, uid))
    rid = user_info['rid']
    if not rid:
        rid = data.get("rid", "")
    all_player_data = []
    sg = SanGong(rid, bid)
    db = dao.Game_DB()
    for member in sg.members:
        p = Player(member, bid, rid)
        player_data = p.get_data()
        player_info = db.get_player(rid, uid)
        player_data['status'] = player_info['status']
        player_data['user_score'] = player_info['score']
        player_data['online'] = player_info['online']
        all_player_data.append(player_data)
    game_round = sg.room['game_round']
    all_round = sg.room['all_round']
    dealer = sg.room['dealer']
    status = sg.room['status']
    pub_data = {"act":"get_last_data",
                "game_round":game_round, 
                "all_round":all_round, 
                "dealer":dealer,
                "status":status,
                "rid":rid,
                "all_player_data":all_player_data,
                }
    nsq_pub({"b":bid, "u":uid, "t":"game", "d":pub_data})
    tips_user = sg.tips_user.members
    if tips_user:
        if uid in tips_user:
            p = Player(uid, bid, rid)
            stop_pop_act = sg.room['stop_pop_act']
            nsq_pub({"b":bid, "u":uid, "t":"game", "d":{"act":stop_pop_act, "uid":uid, "rid":rid}})
        
class Player():
    def __init__(self, uid, bid='', rid='', first=False):
        self.uid = uid
        self.bid = bid
        self.rid = rid
        if first:
            redisco.connection.delete("p:%s:%s:%s:current_card" % (bid, uid, rid))
            redisco.connection.delete("p:%s:%s:%s" % (bid, uid, rid))
            self.pinfo = Hash("p:%s:%s:%s" % (bid, uid, rid))
            self.pinfo['score'] = 0
            self.pinfo['double_value'] = '1'
            self.pinfo['card_type'] = ''
            self.pinfo['max_value'] = ''
            self.pinfo['show_flag'] = 'n'
        else:
            self.pinfo = Hash("p:%s:%s:%s" % (bid, uid, rid))
        self.current_card = List("p:%s:%s:%s:current_card" % (bid, uid, rid))
    
    def clear(self):
        redisco.connection.delete("p:%s:%s:%s:current_card" % (self.bid, self.uid, self.rid))
        redisco.connection.delete("p:%s:%s:%s" % (self.bid, self.uid, self.rid))
        
    def get_data(self):
        return {"uid":self.uid,
                "current_card":self.current_card.members,
                "score":self.pinfo['score'],
                "double_value":self.pinfo['double_value'],
                "card_type":self.pinfo['card_type'],
                "show_flag":self.pinfo['show_flag'],
                #"max_value":self.pinfo['max_value'],
                #"card_type_name":self.pinfo['card_type_name'],
                #"format_card":self.pinfo['format_card'],
                }
        
class SanGong():
    def __init__(self, rid, bid, dealer=None):
        self.rid = str(rid)
        if dealer:
            redisco.connection.delete("r:%s:current_card" % rid)
            redisco.connection.delete("r:%s:mid" % rid)
            redisco.connection.delete("r:%s:tips_user" % rid)
            self.room = Hash("r:%s" % rid)
            self.room['dealer'] = dealer
            self.room['next_dealer'] = ''
            self.room['max_point'] = '0'
            self.room['stop_pop_act'] = ''
        else:
            self.room = Hash("r:%s" % rid)
        self.current_card = List("r:%s:current_card" % rid)
        self.bid = bid
        l = List("r:%s:p" % rid)
        self.members = l.members
        self.tips_user = List("r:%s:tips_user" % rid)
    
    def clear_room(self):
        redisco.connection.delete("r:%s:current_card" % self.rid)
        redisco.connection.delete("r:%s:mid" % self.rid)
        redisco.connection.delete("r:%s:tips_user" % self.rid)
        redisco.connection.delete("r:%s" % self.rid)
            
    def incr_mid(self):
        return redisco.connection.incr("r:%s:mid" % self.rid)
    
    def get_card_point(self, c):
        '''获取某张扑克牌的点数'''
        d = int(c)/10
        if d > 10:
            d = 10
        return d
    
    def trans_card(self, card):
        '''转换手牌列表,去掉花色'''
        res = []
        card.sort()
        for c in card:
            card_point = self.get_card_point(c)
            res.append(card_point)
        return res
    
    def trans_int_card(self, card):
        res = [int(x) for x in card]
        return res
    
    def get_double_value(self, card_type, mode=''):
        value_conf = {"triple_3":9,
                  "triple":5,
                  "sangong":4,
                  "p_9":3,
                  "p_8":2,
                  "p_7":1,
                  "p_6":1,
                  "p_5":1,
                  "p_4":1,
                  "p_3":1,
                  "p_2":1,
                  "p_1":1,
                  "p_0":1,
                  }
        return value_conf[card_type]
    
    def get_point(self, all_card):
        card = self.trans_card(all_card)
        all_card = self.trans_int_card(all_card)
        n = sum(card) % 10
        return 'p_%s' % n, sorted(all_card, reverse=True)
    
    def is_sangong(self, all_card):
        card = [int(c)/10 for c in all_card]
        for c in card:
            if c < 10:
                return False, 0
        all_card = self.trans_int_card(all_card)
        return 'sangong', sorted(all_card, reverse=True)
    
    def is_triple(self, all_card):
        card = [int(c)/10 for c in all_card]
        for c in set(card):
            if card.count(c) == 3:
                return 'triple', sorted(card, reverse=True)
        return False, 0
    
    def is_triple_3(self, all_card):
        card = [int(c)/10 for c in all_card]
        for c in set(card):
            if card.count(c) == 3 and c == 3:
                return 'triple_3', sorted(card, reverse=True)
        return False, 0
    
    def get_card_type(self, all_card):
        is_triple_3 = self.is_triple_3(all_card)
        if is_triple_3[0]:
            return is_triple_3
        is_triple = self.is_triple(all_card)
        if is_triple[0]:
            return is_triple
        is_sangong = self.is_sangong(all_card)
        if is_sangong[0]:
            return is_sangong
        return self.get_point(all_card)
    
    def compare_card(self, card1, card2):
        #判断card2是否比card1牌型大
        card_type_conf = ['p_0', 'p_1', 'p_2', 'p_3', 'p_4', 'p_5', 'p_6', 'p_7', 'p_8', 'p_9', 'sangong', 'triple', 'triple_3',]
        card_type2, card_sort2 = self.get_card_type(card2)
        card_type1, card_sort1 = self.get_card_type(card1)
        c2_idx = card_type_conf.index(card_type2)
        c1_idx = card_type_conf.index(card_type1)
        if c2_idx > c1_idx:
            return True
        elif c2_idx == c1_idx:
            if card_sort2[0] > card_sort1[0]:
                return True
            elif card_sort2[0] == card_sort1[0]:
                if card_sort2[1] > card_sort1[1]:
                    return True
                elif card_sort2[1] == card_sort1[1]:
                    if card_sort2[2] > card_sort1[2]:
                        return True
        return False
    
    def start(self):
        self.room['status'] = 'start'
        game_round = int(self.room['game_round'])
        dealer = self.room['dealer']
        dealer_mode = self.room['dealer_mode']
        #大混战没有庄
        if dealer_mode == 'melee':
            dealer = ''
        
        self.tips_user.clear()
        self.room['stop_pop_act'] = 'turn_double_select'
        for member in self.members:
            player = Player(member, self.bid, self.rid, True)
            nsq_pub({"b":self.bid, "u":member, "t":"game", "d":{"act":"game_start", "dealer_mode":dealer_mode,"dealer":dealer,"rid":self.rid, "game_round":self.room['game_round'], "all_round":self.room['all_round']}})
        
        if dealer_mode == 'melee':
            self.tips_user.extend(self.members)
            self.auto_double_select()
        else:
            self.turn_double_select(dealer)
            
    def turn_double_select(self, dealer):
        self.room['stop_pop_act'] = 'turn_double_select'
        for member in self.members:
            if member != dealer:
                self.tips_user.append(member)
                nsq_pub({"b":self.bid, "u":member, "t":"game", "d":{"act":"turn_double_select", "uid":member, "rid":self.rid}})
        
        timer = Timer(20, self.auto_double_select)
        timer.start()
    
    def auto_double_select(self):
        stop_pop_act = self.room['stop_pop_act']
        if stop_pop_act == 'turn_double_select':
            tips_user = self.tips_user.members
            for uid in tips_user:
                self.double_select(uid, {"double_value":1})
                time.sleep(0.5)
        
    def double_select(self, uid, data):
        #选择加倍
        logging.info(self.tips_user)
        if uid not in self.tips_user.members:
            return
        self.tips_user.remove(uid)
        player = Player(uid, self.bid, self.rid)
        double_value = data['double_value']
        player.pinfo['double_value'] = double_value
        logging.info(u"玩家%s下注%s, %s" % (uid, double_value, player.pinfo['double_value']))
        for member in self.members:
            nsq_pub({"b":self.bid, "u":member, "t":"game", "d":{"act":"double_select", "uid":uid, "double_value":double_value, "rid":self.rid}})
        
        if not self.tips_user:
            self.room['stop_pop_act'] = ''
            self.next_pop()

    def next_pop(self):
        all_card = []
        for i in range(10, 140, 10):
            for j in range(1, 5):
                all_card.append(str(i+j))
        
        random.shuffle(all_card)
        
        dealer = self.room['dealer']
        user_card = {}
        player_card = []
        for uid in self.members:
            card = []
            for i in range(3):
                card.append(all_card.pop())
            card.sort()
            card.reverse()
            user_card[uid] = card
            player_card.append({"uid":uid, "current_card":card})
            
        for uid in self.members:
            mid = self.incr_mid()
            player = Player(uid, self.bid, self.rid)
            card = user_card[uid]
            player.current_card.extend(card)
            card_type, max_value = self.get_card_type(card)
            nsq_pub({"b":self.bid, "u":uid, "t":"game", "d":{"act":"get_card", "rid":self.rid, "mid":mid, "card":card, "card_type":card_type,"game_round":self.room['game_round'], "all_round":self.room['all_round'], "player_card":player_card}})
        self.current_card.clear()
        
        logging.info(u"三公房间rid:%s,game_round:%s,发牌结束" % (self.rid, self.room['game_round']))
        
        self.room['stop_pop_act'] = 'turn_show_res'
        self.tips_user.extend(self.members)
        for member in self.members:
            nsq_pub({"b":self.bid, "u":member, "t":"game", "d":{"act":"turn_show_res", "uid":member, "rid":self.rid}})
        
        timer = Timer(15, self.auto_show_res)
        timer.start()
    
    def show_res(self, uid, data={}):
        stop_pop_act = self.room['stop_pop_act']
        
        if stop_pop_act != 'turn_show_res':
            return
        tips_user = self.tips_user.members
        if uid not in tips_user:
            return
        player = Player(uid, self.bid, self.rid)
        card = player.current_card.members
        card_type, max_value = self.get_card_type(card)
        player.pinfo['card_type'] = card_type
        player.pinfo['max_value'] = max_value
        player.pinfo['show_flag'] = 'y'
        if card_type == 'p_9' and self.room['dealer_mode'] == 'p_9':
            max_point = int(self.room['max_point'])
            if max_value > max_point:
                self.room['max_point'] = max_value
                self.room['next_dealer'] = uid
                
        for member in self.members:
            nsq_pub({"b":self.bid, "u":member, "t":"game", "d":{"act":"show_res", "uid":uid, "card_type":card_type, "card":card, "rid":self.rid}})
        self.tips_user.remove(uid)
        if not self.tips_user.members:
            self.room['stop_pop_act'] = ''
            self.game_over()
            
    def auto_show_res(self):
        stop_pop_act = self.room['stop_pop_act']
        #if stop_pop_act != 'show_res':
        #    return
        for member in self.tips_user.members:
            self.show_res(member)
            time.sleep(0.5)
        
    def game_over(self, next_dealer='', from_dissmiss=False):
        dealer_mode = self.room['dealer_mode']
        logging.info(self.room)
        dealer = self.room['dealer']
        base_score = self.room['base']
        if not base_score:
            base_score = 1
        else:
            base_score = int(base_score)
                
        db = dao.Game_DB()
        if dealer_mode == 'melee':
            for (p1_uid, p2_uid) in itertools.combinations(self.members, 2):
                p1 = Player(p1_uid, self.bid, self.rid)
                p2 = Player(p2_uid, self.bid, self.rid)
                p1_card = p1.current_card.members
                p2_card = p2.current_card.members
                compare_res = self.compare_card(p1_card, p2_card)
                if compare_res:
                    double_value = int(p1.pinfo['double_value'])
                    card_type = p2.pinfo['card_type']
                    card_double = self.get_double_value(card_type)
                    
                    win_score = card_double*double_value*base_score
                    p2.pinfo['score'] = int(p2.pinfo['score']) + win_score
                    db.update_player(self.rid, p2_uid, win_score, 0)
                    p1.pinfo['score'] = int(p1.pinfo['score']) - win_score
                    db.update_player(self.rid, p1_uid, -win_score, 0)
                else:
                    double_value = int(p2.pinfo['double_value'])
                    card_type = p1.pinfo['card_type']
                    card_double = self.get_double_value(card_type)
                    win_score = card_double*double_value*base_score
                    p2.pinfo['score'] = int(p2.pinfo['score']) - win_score
                    db.update_player(self.rid, p2_uid, -win_score, 0)
                    p1.pinfo['score'] = int(p1.pinfo['score']) + win_score
                    db.update_player(self.rid, p1_uid, win_score, 0)
                db.commit()
        else:
            members = self.members
            player_cnt = len(members)
            dealer_seat = members.index(dealer)
            dealer_player = Player(dealer, self.bid, self.rid)
            dealer_card = dealer_player.current_card.members
            
            #for i in range(1, player_cnt):
            for member in members:
                try:
                    if member == dealer:
                        continue
                    #idx = (dealer_seat + i) % player_cnt
                    #member = members[idx]
                    member_player = Player(member, self.bid, self.rid)
                    member_card = member_player.current_card.members
                    double_value = int(member_player.pinfo['double_value'])
                    compare_res = self.compare_card(dealer_card, member_card)
                    
                    if compare_res:
                        card_type = member_player.pinfo['card_type']
                        card_double = self.get_double_value(card_type)
                        win_score = card_double*double_value*base_score
                        member_player.pinfo['score'] = win_score
                        db.update_player(self.rid, member, win_score, 0)
                        dealer_player.pinfo['score'] = int(dealer_player.pinfo['score']) - win_score
                        db.update_player(self.rid, dealer, -win_score, 0)
                        logging.info(u"闲家%s赢base:%s, double:%s, card_double:%s" % (member, base_score, double_value, card_double))
                    else:
                        card_type = dealer_player.pinfo['card_type']
                        card_double = self.get_double_value(card_type)
                        win_score = card_double*double_value*base_score
                        member_player.pinfo['score'] = -win_score
                        db.update_player(self.rid, member, -win_score, 0)
                        dealer_player.pinfo['score'] = int(dealer_player.pinfo['score']) + win_score
                        db.update_player(self.rid, dealer, win_score, 0)
                        logging.info(u"庄家赢base:%s, double:%s, card_double:%s" % (base_score, double_value, card_double))
                    db.commit()
                except:
                    logging.error(u"errro:", exc_info=True)
        game_round = self.room['game_round']
        if not game_round:
            game_round = 1
        else:
            game_round = int(game_round)
        all_round = int(self.room['all_round'])
        player_card = []
        card_type_conf = {"triple_3":u"爆3",
                          "triple":u"三条",
                          "sangong":u"三公",
                          "p_9":u"9点",
                          "p_8":u"8点",
                          "p_7":u"7点",
                          "p_6":u"6点",
                          "p_5":u"5点",
                          "p_4":u"4点",
                          "p_3":u"3点",
                          "p_2":u"2点",
                          "p_1":u"1点",
                          "p_0":u"0点",
                          }
        for member in self.members:
            player_info = db.get_player(self.rid, member)
            member_player = Player(member, self.bid, self.rid)
            user_card = member_player.current_card.members
            if member == dealer:
                is_dealer = 'y'
            else:
                is_dealer = 'n'
            win_score = member_player.pinfo['score']
            card_type = member_player.pinfo['card_type']
            card_type_name = card_type_conf[card_type]
            user_data= {"is_dealer":is_dealer, "card_type":card_type, "card_type_name":card_type_name,"user_card":user_card, "win_score":win_score, "user_score":player_info['score'], "uid":member}
            player_card.append(user_data)
            db.add_dn_room_log(0, 0, self.rid, game_round, member, win_score, 0, 0, 0, 0, 0, 0, 0)
            db.commit()
            member_player.current_card.clear()
            
        room_over = 'n'
        if from_dissmiss or game_round >= all_round:
            room_over = 'y'
        
        db.game_over(self.rid, game_round)
        db.commit()
        mid = self.incr_mid()
        game_type = self.room['game_type']
        if next_dealer:
            self.room['dealer'] = next_dealer
        self.room['game_round'] = game_round + 1
        self.room['status'] = 'over'
        logging.info(self.members)
        for member in self.members:
            pub_data = {"b":self.bid, "u":member, "t":"game", "d":{"mid":mid, "act":"game_over", "room_over":room_over, "game_type":game_type, "dealer":dealer, "player_card":player_card, "game_round":game_round, "rid":self.rid,}}
            nsq_pub(pub_data)
            #db.save_game_over(self.rid, game_round, "game_over", member, urllib.quote(json_encode(pub_data).encode("utf-8")))
            #db.commit()
        if room_over == 'y':
            self.dismiss()
    
    def dismiss(self):
        db = dao.Game_DB()
        #player_data = {}
        player_stat = []
        
        p_stat = db.player_stat_dn(self.rid)
        if p_stat:
            winner = p_stat[-1]['uid']
            max_score = p_stat[-1]['score']
            for ps in p_stat:
                if ps['score'] == max_score:
                    is_winner = 'y'
                else:
                    is_winner = 'n'
                player_stat.append({"uid":ps['uid'], "score":str(ps['score']), "is_winner":is_winner})
                #player_data[str(ps['uid'])] = ps
        
        else:
            winner = ""
            for member in self.members:
                player_stat.append({"uid":member, "score":"0", "is_winner":"n"})
            
            
        room_info = db.get_room(self.rid, self.bid)
        admin = room_info['admin']
        #match_id = room_info['mid']
        #gid = room_info['gid']
        #if not gid:
        #    gid = 0
        #for ps in player_stat:
        #    if ps['uid'] == winner:
        #        is_winner = 'y'
        #    else:
        #        is_winner = 'n'
        #    db.add_room_stat(match_id, gid, self.rid, ps['uid'], ps['score'], is_winner)
        #    db.commit()
        
        all_round = self.room['all_round']
        dealer_mode = self.room['dealer_mode']
        base = self.room['base']
        for member in self.members:
            if not member:
                continue
            pub_data = {"b":self.bid, "u":member, "t":"game", "d":{"act":"room_over", "rid":self.rid, "player_stat":player_stat, "winner":winner, "admin":admin, "all_round":all_round, "base":base, "dealer_mode":dealer_mode}}
            nsq_pub(pub_data)
            #db.save_game_over(self.rid, 0, "room_over", member, json_encode(pub_data))
            #db.commit()
            
        db.dismiss_room(self.rid)
        db.commit()
            
        for member in self.members:
            member_player = Player(member, self.bid, self.rid)
            member_player.clear()
        self.clear_room()
    
    
    
